<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebSocket压力测试</title>
    <link rel="stylesheet" href="css/websocket-test.css">
    <style>
        .metrics-grid {
            display: grid;
            grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
            gap: 15px;
            margin-top: 10px;
        }
        
        .metric-card {
            background: white;
            border-radius: 8px;
            padding: 20px;
            box-shadow: 0 2px 6px rgba(0,0,0,0.1);
            display: flex;
            flex-direction: column;
            align-items: center;
            text-align: center;
        }
        
        .metric-value {
            font-size: 24px;
            font-weight: bold;
            margin: 10px 0;
        }
        
        .metric-label {
            color: #666;
            font-size: 14px;
        }
        
        .metric-unit {
            color: #999;
            font-size: 12px;
        }
        
        .progress-bar-container {
            width: 100%;
            height: 10px;
            background-color: #f0f0f0;
            border-radius: 5px;
            overflow: hidden;
            margin: 10px 0;
        }
        
        .progress-bar {
            height: 100%;
            background-color: #4caf50;
            width: 0;
            transition: width 0.3s ease;
        }
        
        .test-controls {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 15px;
        }
        
        .test-option-card {
            background: white;
            border-radius: 8px;
            padding: 15px;
            box-shadow: 0 2px 6px rgba(0,0,0,0.1);
        }
        
        .test-option-title {
            font-weight: bold;
            margin-bottom: 15px;
            border-bottom: 1px solid #eee;
            padding-bottom: 10px;
        }
        
        .console-output {
            background-color: #2b2b2b;
            color: #f8f8f8;
            border-radius: 8px;
            padding: 10px;
            height: 300px;
            overflow-y: auto;
            font-family: monospace;
            white-space: pre-wrap;
            word-break: break-all;
        }
        
        .console-output .system {
            color: #8bc34a;
        }
        
        .console-output .error {
            color: #f44336;
        }
        
        .console-output .warning {
            color: #ffc107;
        }
        
        .console-output .info {
            color: #2196f3;
        }
        
        .client-list {
            max-height: 300px;
            overflow-y: auto;
        }
        
        .client-item {
            display: flex;
            align-items: center;
            padding: 8px;
            border-bottom: 1px solid #eee;
        }
        
        .client-status {
            width: 10px;
            height: 10px;
            border-radius: 50%;
            margin-right: 10px;
        }
        
        .client-status.connected {
            background-color: #4caf50;
        }
        
        .client-status.connecting {
            background-color: #ff9800;
        }
        
        .client-status.disconnected {
            background-color: #f44336;
        }
        
        .client-id {
            flex-grow: 1;
        }
        
        .client-sent, .client-received {
            margin-left: 15px;
            font-size: 12px;
            color: #666;
        }
        
        .btn-group {
            display: flex;
            gap: 10px;
            margin-top: 15px;
        }
        
        .chart-container {
            width: 100%;
            height: 200px;
            position: relative;
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>WebSocket压力测试</h1>
        <div class="notification notification-info">
            该页面用于测试系统在高并发、大量消息情况下的性能表现
        </div>

        <div class="row">
            <div class="col">
                <div class="card">
                    <h2 class="card-header">连接设置</h2>
                    <div class="form-group">
                        <label for="endpoint">WebSocket端点</label>
                        <input type="text" id="endpoint" value="/ChatMessageServer" placeholder="例如 /ChatMessageServer">
                    </div>
                    <div class="form-group">
                        <label for="baseUsername">基础用户名</label>
                        <input type="text" id="baseUsername" value="stress_test_" placeholder="例如 stress_test_">
                        <small class="text-muted">将自动添加数字后缀，如 stress_test_1, stress_test_2...</small>
                    </div>
                </div>
            </div>
        </div>

        <div class="test-controls mt-3">
            <div class="test-option-card">
                <h3 class="test-option-title">连接测试</h3>
                <div class="form-group">
                    <label for="connectionCount">连接数量</label>
                    <input type="number" id="connectionCount" class="form-control" value="10" min="1" max="1000">
                </div>
                <div class="form-group">
                    <label for="connectionInterval">连接间隔 (毫秒)</label>
                    <input type="number" id="connectionInterval" class="form-control" value="200" min="10" max="5000">
                </div>
                <div class="form-group">
                    <div class="progress-bar-container">
                        <div id="connectionProgressBar" class="progress-bar"></div>
                    </div>
                    <div id="connectionStatus">准备就绪</div>
                </div>
                <div class="btn-group">
                    <button id="startConnectionTestBtn" class="btn btn-primary w-100">开始测试</button>
                    <button id="stopConnectionTestBtn" class="btn btn-secondary w-100" disabled>停止测试</button>
                </div>
            </div>
            
            <div class="test-option-card">
                <h3 class="test-option-title">消息测试</h3>
                <div class="form-group">
                    <label for="messageCount">每个连接发送消息数</label>
                    <input type="number" id="messageCount" class="form-control" value="10" min="1" max="1000">
                </div>
                <div class="form-group">
                    <label for="messageInterval">发送间隔 (毫秒)</label>
                    <input type="number" id="messageInterval" class="form-control" value="500" min="10" max="5000">
                </div>
                <div class="form-group">
                    <label for="messageSize">消息大小 (字节)</label>
                    <input type="number" id="messageSize" class="form-control" value="100" min="10" max="1000000">
                </div>
                <div class="form-group">
                    <div class="progress-bar-container">
                        <div id="messageProgressBar" class="progress-bar"></div>
                    </div>
                    <div id="messageStatus">准备就绪</div>
                </div>
                <div class="btn-group">
                    <button id="startMessageTestBtn" class="btn btn-primary w-100" disabled>开始测试</button>
                    <button id="stopMessageTestBtn" class="btn btn-secondary w-100" disabled>停止测试</button>
                </div>
            </div>
        </div>

        <div class="row mt-3">
            <div class="col">
                <div class="card">
                    <h2 class="card-header">性能指标</h2>
                    <div class="metrics-grid p-3">
                        <div class="metric-card">
                            <div class="metric-label">连接成功率</div>
                            <div id="connectionSuccessRate" class="metric-value">0%</div>
                        </div>
                        <div class="metric-card">
                            <div class="metric-label">平均连接时间</div>
                            <div id="avgConnectionTime" class="metric-value">0</div>
                            <div class="metric-unit">毫秒</div>
                        </div>
                        <div class="metric-card">
                            <div class="metric-label">消息成功率</div>
                            <div id="messageSuccessRate" class="metric-value">0%</div>
                        </div>
                        <div class="metric-card">
                            <div class="metric-label">消息吞吐量</div>
                            <div id="messageThroughput" class="metric-value">0</div>
                            <div class="metric-unit">条/秒</div>
                        </div>
                        <div class="metric-card">
                            <div class="metric-label">平均响应时间</div>
                            <div id="avgResponseTime" class="metric-value">0</div>
                            <div class="metric-unit">毫秒</div>
                        </div>
                        <div class="metric-card">
                            <div class="metric-label">已连接客户端</div>
                            <div id="connectedClients" class="metric-value">0</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

        <div class="row mt-3">
            <div class="col" style="flex: 1;">
                <div class="card">
                    <h2 class="card-header">客户端列表</h2>
                    <div id="clientList" class="client-list p-2">
                        <!-- 客户端列表将在这里动态生成 -->
                        <div class="text-muted text-center p-3">尚未创建客户端</div>
                    </div>
                </div>
            </div>
            <div class="col" style="flex: 2;">
                <div class="card">
                    <h2 class="card-header">控制台输出</h2>
                    <div id="console" class="console-output">
                        <!-- 控制台输出将在这里显示 -->
                        <div class="system"># 压力测试控制台就绪，等待开始测试...</div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script src="js/websocket-client.js"></script>
    <script>
    // 页面元素
    const endpoint = document.getElementById('endpoint');
    const baseUsername = document.getElementById('baseUsername');
    const connectionCount = document.getElementById('connectionCount');
    const connectionInterval = document.getElementById('connectionInterval');
    const connectionProgressBar = document.getElementById('connectionProgressBar');
    const connectionStatus = document.getElementById('connectionStatus');
    const startConnectionTestBtn = document.getElementById('startConnectionTestBtn');
    const stopConnectionTestBtn = document.getElementById('stopConnectionTestBtn');
    
    const messageCount = document.getElementById('messageCount');
    const messageInterval = document.getElementById('messageInterval');
    const messageSize = document.getElementById('messageSize');
    const messageProgressBar = document.getElementById('messageProgressBar');
    const messageStatus = document.getElementById('messageStatus');
    const startMessageTestBtn = document.getElementById('startMessageTestBtn');
    const stopMessageTestBtn = document.getElementById('stopMessageTestBtn');
    
    const connectionSuccessRate = document.getElementById('connectionSuccessRate');
    const avgConnectionTime = document.getElementById('avgConnectionTime');
    const messageSuccessRate = document.getElementById('messageSuccessRate');
    const messageThroughput = document.getElementById('messageThroughput');
    const avgResponseTime = document.getElementById('avgResponseTime');
    const connectedClients = document.getElementById('connectedClients');
    
    const clientList = document.getElementById('clientList');
    const consoleOutput = document.getElementById('console');
    
    // 测试变量
    let clients = [];
    let connectTestRunning = false;
    let messageTestRunning = false;
    let connectTestTimer = null;
    let messageTestTimer = null;
    
    // 性能指标
    let metrics = {
        connectionAttempts: 0,
        connectionSuccesses: 0,
        connectionTimes: [],
        messagesSent: 0,
        messagesReceived: 0,
        responseTimes: [],
        testStartTime: 0
    };
    
    // 初始化
    function init() {
        // 绑定按钮事件
        startConnectionTestBtn.addEventListener('click', startConnectionTest);
        stopConnectionTestBtn.addEventListener('click', stopConnectionTest);
        startMessageTestBtn.addEventListener('click', startMessageTest);
        stopMessageTestBtn.addEventListener('click', stopMessageTest);
        
        // 从URL参数获取值
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.has('endpoint')) {
            endpoint.value = urlParams.get('endpoint');
        }
        if (urlParams.has('baseUsername')) {
            baseUsername.value = urlParams.get('baseUsername');
        }
    }
    
    // 连接测试
    function startConnectionTest() {
        // 重置上一次测试数据
        resetTestData();
        
        const count = parseInt(connectionCount.value);
        const interval = parseInt(connectionInterval.value);
        
        if (count <= 0 || interval <= 0) {
            log('error', '连接数量和间隔必须大于0');
            return;
        }
        
        // 禁用按钮
        startConnectionTestBtn.disabled = true;
        stopConnectionTestBtn.disabled = false;
        
        // 清空客户端列表
        clients = [];
        clientList.innerHTML = '';
        
        // 更新状态
        connectTestRunning = true;
        metrics.testStartTime = Date.now();
        log('system', `开始连接测试: ${count}个连接, 间隔${interval}毫秒`);
        
        // 开始创建连接
        let clientIndex = 0;
        
        connectTestTimer = setInterval(() => {
            if (clientIndex < count && connectTestRunning) {
                createClient(clientIndex);
                
                // 更新进度条
                const progress = (clientIndex + 1) / count * 100;
                connectionProgressBar.style.width = `${progress}%`;
                connectionStatus.textContent = `已连接 ${clientIndex + 1}/${count}`;
                
                clientIndex++;
            } else {
                clearInterval(connectTestTimer);
                
                if (connectTestRunning) {
                    log('system', '所有连接创建完成');
                    connectionStatus.textContent = `已完成 ${clients.filter(c => c.connected).length}/${count} 连接`;
                    
                    // 启用消息测试按钮
                    startMessageTestBtn.disabled = false;
                }
            }
        }, interval);
    }
    
    // 停止连接测试
    function stopConnectionTest() {
        if (connectTestTimer) {
            clearInterval(connectTestTimer);
        }
        
        connectTestRunning = false;
        stopConnectionTestBtn.disabled = true;
        startConnectionTestBtn.disabled = false;
        
        log('system', '连接测试已停止');
        connectionStatus.textContent = '测试已停止';
        
        // 断开所有连接
        disconnectAllClients();
    }
    
    // 消息测试
    function startMessageTest() {
        const msgCount = parseInt(messageCount.value);
        const msgInterval = parseInt(messageInterval.value);
        const msgSize = parseInt(messageSize.value);
        
        if (msgCount <= 0 || msgInterval <= 0 || msgSize <= 0) {
            log('error', '消息数量、间隔和大小必须大于0');
            return;
        }
        
        // 检查是否有连接的客户端
        const activeClients = clients.filter(client => client.connected);
        if (activeClients.length === 0) {
            log('error', '没有连接的客户端可以发送消息');
            return;
        }
        
        // 禁用按钮
        startMessageTestBtn.disabled = true;
        stopMessageTestBtn.disabled = false;
        
        // 更新状态
        messageTestRunning = true;
        messageProgressBar.style.width = '0%';
        messageStatus.textContent = '正在发送消息...';
        metrics.testStartTime = Date.now();
        
        log('system', `开始消息测试: 每个客户端发送${msgCount}条消息, 大小${msgSize}字节, 间隔${msgInterval}毫秒`);
        
        // 生成测试消息内容
        const messageContent = generateRandomString(msgSize);
        
        // 每个客户端发送消息
        let messagesSent = 0;
        const totalMessages = activeClients.length * msgCount;
        
        // 每个客户端的进度
        const clientProgress = {};
        activeClients.forEach(client => {
            clientProgress[client.id] = 0;
        });
        
        const sendNextMessages = () => {
            if (!messageTestRunning) {
                clearInterval(messageTestTimer);
                return;
            }
            
            // 每个活跃的客户端发送一条消息
            activeClients.forEach(client => {
                if (clientProgress[client.id] < msgCount) {
                    // 创建Echo消息
                    const echoMessage = {
                        type: 'chat',
                        fromUser: client.id,
                        toUser: client.id, // 发给自己做echo测试
                        contentType: 'text',
                        content: messageContent,
                        timestamp: Date.now()
                    };
                    
                    // 记录发送时间
                    const sendTime = Date.now();
                    echoMessage.sendTime = sendTime;
                    
                    // 发送消息
                    client.instance.sendMessage(echoMessage);
                    metrics.messagesSent++;
                    client.messagesSent++;
                    
                    clientProgress[client.id]++;
                    messagesSent++;
                    
                    // 更新客户端显示
                    updateClientDisplay(client);
                }
            });
            
            // 更新进度条
            const progress = Math.min(messagesSent / totalMessages * 100, 100);
            messageProgressBar.style.width = `${progress}%`;
            messageStatus.textContent = `已发送 ${messagesSent}/${totalMessages} 条消息`;
            
            // 计算当前吞吐量
            updateMetricsDisplay();
            
            // 检查是否完成
            if (messagesSent >= totalMessages) {
                clearInterval(messageTestTimer);
                log('system', '消息测试完成');
                messageStatus.textContent = '测试完成';
                
                // 重新启用按钮
                startMessageTestBtn.disabled = false;
                stopMessageTestBtn.disabled = true;
                messageTestRunning = false;
            }
        };
        
        // 开始定时发送
        messageTestTimer = setInterval(sendNextMessages, msgInterval);
    }
    
    // 停止消息测试
    function stopMessageTest() {
        if (messageTestTimer) {
            clearInterval(messageTestTimer);
        }
        
        messageTestRunning = false;
        stopMessageTestBtn.disabled = true;
        startMessageTestBtn.disabled = false;
        
        log('system', '消息测试已停止');
        messageStatus.textContent = '测试已停止';
    }
    
    // 创建客户端
    function createClient(index) {
        const clientId = `${baseUsername.value}${index + 1}`;
        const endpointUrl = endpoint.value;
        
        metrics.connectionAttempts++;
        
        log('info', `Creating client ${clientId}...`);
        
        const connectionStart = Date.now();
        
        // 创建客户端元素
        const clientElement = document.createElement('div');
        clientElement.className = 'client-item';
        clientElement.id = `client-${clientId}`;
        clientElement.innerHTML = `
            <div class="client-status connecting"></div>
            <div class="client-id">${clientId}</div>
            <div class="client-sent">发送: 0</div>
            <div class="client-received">接收: 0</div>
        `;
        
        clientList.appendChild(clientElement);
        
        // 创建客户端对象
        const client = {
            id: clientId,
            connected: false,
            instance: null,
            element: clientElement,
            messagesSent: 0,
            messagesReceived: 0
        };
        
        // 创建WebSocket客户端
        try {
            const wsClient = new WebSocketClient(endpointUrl, clientId, {
                onConnect: () => {
                    const connectionTime = Date.now() - connectionStart;
                    log('info', `Client ${clientId} connected in ${connectionTime}ms`);
                    
                    // 更新统计信息
                    metrics.connectionSuccesses++;
                    metrics.connectionTimes.push(connectionTime);
                    client.connected = true;
                    
                    // 更新客户端元素
                    const statusEl = clientElement.querySelector('.client-status');
                    statusEl.className = 'client-status connected';
                    
                    // 更新统计显示
                    updateMetricsDisplay();
                },
                onDisconnect: (event) => {
                    log('info', `Client ${clientId} disconnected`);
                    client.connected = false;
                    
                    // 更新客户端元素
                    const statusEl = clientElement.querySelector('.client-status');
                    statusEl.className = 'client-status disconnected';
                    
                    // 更新统计显示
                    updateMetricsDisplay();
                },
                onMessage: (message) => {
                    // 处理Echo消息
                    if (message.type === 'chat' && message.fromUser === clientId && message.toUser === clientId) {
                        // 计算响应时间
                        if (message.sendTime) {
                            const responseTime = Date.now() - message.sendTime;
                            metrics.responseTimes.push(responseTime);
                            metrics.messagesReceived++;
                            client.messagesReceived++;
                            
                            // 更新客户端显示
                            updateClientDisplay(client);
                        }
                    }
                },
                onError: (error) => {
                    log('error', `Client ${clientId} error: ${error.message}`);
                }
            });
            
            client.instance = wsClient;
            clients.push(client);
            
            // 连接
            wsClient.connect();
        } catch (error) {
            log('error', `Client ${clientId} creation failed: ${error.message}`);
            
            // 更新客户端元素
            const statusEl = clientElement.querySelector('.client-status');
            statusEl.className = 'client-status disconnected';
        }
    }
    
    // 更新客户端显示
    function updateClientDisplay(client) {
        const clientEl = document.getElementById(`client-${client.id}`);
        if (clientEl) {
            const sentEl = clientEl.querySelector('.client-sent');
            const receivedEl = clientEl.querySelector('.client-received');
            
            sentEl.textContent = `发送: ${client.messagesSent}`;
            receivedEl.textContent = `接收: ${client.messagesReceived}`;
        }
    }
    
    // 断开所有连接
    function disconnectAllClients() {
        clients.forEach(client => {
            if (client.instance && client.connected) {
                client.instance.disconnect();
            }
        });
        
        // 更新UI
        updateMetricsDisplay();
    }
    
    // 更新性能指标显示
    function updateMetricsDisplay() {
        // 连接成功率
        const successRate = metrics.connectionAttempts > 0 
            ? (metrics.connectionSuccesses / metrics.connectionAttempts * 100).toFixed(1)
            : 0;
        connectionSuccessRate.textContent = `${successRate}%`;
        
        // 平均连接时间
        const avgConnTime = metrics.connectionTimes.length > 0 
            ? Math.round(metrics.connectionTimes.reduce((a, b) => a + b, 0) / metrics.connectionTimes.length)
            : 0;
        avgConnectionTime.textContent = avgConnTime;
        
        // 消息成功率
        const msgSuccessRate = metrics.messagesSent > 0 
            ? (metrics.messagesReceived / metrics.messagesSent * 100).toFixed(1) 
            : 0;
        messageSuccessRate.textContent = `${msgSuccessRate}%`;
        
        // 消息吞吐量
        const elapsedSecs = (Date.now() - metrics.testStartTime) / 1000;
        const throughput = elapsedSecs > 0 ? (metrics.messagesReceived / elapsedSecs).toFixed(1) : 0;
        messageThroughput.textContent = throughput;
        
        // 平均响应时间
        const avgRespTime = metrics.responseTimes.length > 0
            ? Math.round(metrics.responseTimes.reduce((a, b) => a + b, 0) / metrics.responseTimes.length)
            : 0;
        avgResponseTime.textContent = avgRespTime;
        
        // 已连接客户端
        const connected = clients.filter(c => c.connected).length;
        connectedClients.textContent = connected;
    }
    
    // 重置测试数据
    function resetTestData() {
        metrics = {
            connectionAttempts: 0,
            connectionSuccesses: 0,
            connectionTimes: [],
            messagesSent: 0,
            messagesReceived: 0,
            responseTimes: [],
            testStartTime: 0
        };
        updateMetricsDisplay();
    }
    
    // 生成随机字符串
    function generateRandomString(length) {
        const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
        let result = '';
        for (let i = 0; i < length; i++) {
            result += chars.charAt(Math.floor(Math.random() * chars.length));
        }
        return result;
    }
    
    // 写入日志
    function log(type, message) {
        const logElement = document.createElement('div');
        logElement.className = type;
        
        const timestamp = new Date().toLocaleTimeString();
        logElement.textContent = `[${timestamp}] ${message}`;
        
        consoleOutput.appendChild(logElement);
        consoleOutput.scrollTop = consoleOutput.scrollHeight;
    }
    
    // 页面初始化
    document.addEventListener('DOMContentLoaded', init);
    </script>
</body>
</html> 
</html> 